package com.example.demo.excel.support;

import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateExceptionHandler;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
import java.util.Map;

public class FreemarkerUtils {

    private static final Logger log = LoggerFactory.getLogger(FreemarkerUtils.class);

    /**
     * 使用模板导出数据到excel文件
     *
     * @param dataMap      组织完成的需要填充的数据
     * @param templateFile 模板文件
     * @param outputFile   需要保存到的文件（导出excel到这个文件）
     */
    public static void exportToFile(
        Map dataMap,
        File templateFile,
        File outputFile
    ) {
        try {
            final String templateFileName = templateFile.getName();
            final String templateFilePath = templateFile.getParentFile().getPath();
            FileOutputStream outputStream = new FileOutputStream(outputFile);
            exportToStream(dataMap, templateFileName, templateFilePath, outputStream);
        } catch (Exception exception) {
            log.error("freemarker export to file exception", exception);
        }
    }

    /**
     * 使用模板导出数据到excel文件
     *
     * @param dataMap          组织完成的需要填充的数据
     * @param templateName     模板文件（如有后缀需要带上，例如：file.ftl）
     * @param templateFilePath 模板文件的父文件夹路径
     * @param outputFile       需要保存到的文件
     */
    public static void exportToFile(
        Map dataMap,
        String templateName,
        String templateFilePath,
        String outputFile
    ) {
        try {
            File file = new File(outputFile);
            FileUtils.forceMkdirParent(file);
            FileOutputStream outputStream = new FileOutputStream(file);
            exportToStream(dataMap, templateName, templateFilePath, outputStream);
        } catch (Exception exception) {
            log.error("freemarker export to file exception", exception);
        }
    }

    /**
     * 使用模板导出数据到excel文件输出流
     *
     * @param dataMap          组织完成的需要填充的数据
     * @param templateName     模板文件（如有后缀需要带上，例如：file.ftl）
     * @param templateFilePath 模板文件的父文件夹路径
     * @param outputStream     需要保存到的文件的输出流
     */
    public static void exportToStream(
        Map dataMap,
        String templateName,
        String templateFilePath,
        FileOutputStream outputStream
    ) {
        try {
            Template template = getTemplate(templateName, templateFilePath);
            OutputStreamWriter streamWriter =
                new OutputStreamWriter(outputStream, StandardCharsets.UTF_8);
            Writer writer = new BufferedWriter(streamWriter);
            template.process(dataMap, writer);
            writer.flush();
            writer.close();
            streamWriter.close();
            outputStream.close();
        } catch (Exception exception) {
            log.error("freemarker export to stream exception", exception);
        }
    }

    /**
     * 获取template模板
     *
     * @param templateName     template文件名(带后缀)（例如：file.ftl）
     * @param templateFilePath template文件路径（例如：/usr/data/templates/file.ftl
     *                         或 /usr/data/templates）
     * @return template
     * @throws IOException ex
     */
    private static Template getTemplate(String templateName, String templateFilePath)
        throws IOException {
        Configuration configuration = new Configuration(Configuration.VERSION_2_3_28);
        configuration.setDefaultEncoding("UTF-8");
        configuration.setTemplateUpdateDelayMilliseconds(0);
        configuration.setEncoding(Locale.CHINA, "UTF-8");
        configuration.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);

        File file = new File(templateFilePath);
        if (!file.isDirectory()) {
            file = file.getParentFile();
        }
        configuration.setDirectoryForTemplateLoading(file);
        configuration.setOutputEncoding("UTF-8");
        return configuration.getTemplate(templateName, "UTF-8");
    }
}
